/*
 * PacketQueue.cpp
 *
 *  Created on: 2016年3月17日
 *      Author: terry
 */

#include "PacketQueue.h"

namespace av
{

PacketQueue::PacketQueue()
{
}

PacketQueue::~PacketQueue()
{
}

size_t PacketQueue::size()
{
    comn::AutoCritSec   lock(m_cs);
    return m_packets.size();
}

bool PacketQueue::empty()
{
    comn::AutoCritSec   lock(m_cs);
    return m_packets.empty();
}

size_t PacketQueue::push(AVPacketPtr& packet)
{
    size_t count = 0;
    {
        comn::AutoCritSec   lock(m_cs);
        m_packets.push_back(packet);

        count = m_packets.size();
    }

    m_event.post();
    return count;
}

AVPacketPtr PacketQueue::pop()
{
    AVPacketPtr packet;
    pop(packet);
    return packet;
}

bool PacketQueue::pop(AVPacketPtr& packet)
{
    bool found = false;
    comn::AutoCritSec   lock(m_cs);
    if (!m_packets.empty())
    {
        packet = m_packets.front();
        m_packets.pop_front();
        found = true;
    }
    return found;
}

void PacketQueue::clear()
{
    {
        comn::AutoCritSec   lock(m_cs);
        m_packets.clear();
    }

    m_event.post();
}

bool PacketQueue::timedwait(int ms)
{
    return m_event.timedwait(ms);
}

bool PacketQueue::pop(AVPacketPtr& packet, int ms)
{
    if (empty())
    {
        timedwait(ms);
    }
    return pop(packet);
}

bool PacketQueue::popSize(AVPacketPtr& packet, size_t& count)
{
    bool found = false;
    comn::AutoCritSec   lock(m_cs);
    count = m_packets.size();
    if (count > 0)
    {
        packet = m_packets.front();
        m_packets.pop_front();
        found = true;
        count -= 1;
    }
    return found;
}

size_t PacketQueue::popTimeout(AVPacketPtr& packet, int ms)
{
    size_t count = 0;
    if (popSize(packet, count))
    {
        return count;
    }

    if (!timedwait(ms))
    {
        return 0;
    }

    popSize(packet, count);
    return count;
}

void PacketQueue::cancelWait()
{
    m_event.post();
}

size_t PacketQueue::dropUntilKeyFrame()
{
    size_t count = 0;
    comn::AutoCritSec   lock(m_cs);

    size_t keyIdx = -1;
    for (size_t i = m_packets.size(); i > 0; -- i)
    {
        size_t idx = i - 1;
        AVPacketPtr& packet = m_packets[idx];
        if (isVideoKey(packet))
        {
            keyIdx = idx;

            for (i = keyIdx; i > 0; -- i)
            {
                idx = i - 1;
                AVPacketPtr& packet = m_packets[idx];
                if (isVideoKey(packet))
                {
                    keyIdx = idx;
                }
                else
                {
                    break;
                }
            }

            break;
        }
    }

    if (keyIdx == (size_t)-1)
    {
        return 0;
    }

    count = keyIdx;

    PacketDeque::iterator itBegin = m_packets.begin();
    PacketDeque::iterator it = m_packets.begin();
    std::advance(it, keyIdx);

    m_packets.erase(itBegin, it);

    return count;
}

bool PacketQueue::isVideoKey(AVPacketPtr& pkt)
{
	return ((pkt->flags & AV_PKT_FLAG_KEY) != 0) && (pkt->stream_index == MEDIA_TYPE_VIDEO);
}




} /* namespace av */
